package com.solon.open.service;

import com.alibaba.dashscope.embeddings.MultiModalEmbeddingResult;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.solon.open.config.MinioConfig;
import com.solon.open.mapper.ImageMilvusMapper;
import com.solon.open.model.ImageModel;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.MinioException;
import org.dromara.milvus.plus.model.vo.MilvusResp;
import org.dromara.milvus.plus.model.vo.MilvusResult;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.handle.UploadedFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Component
public class ImageService {
 
    @Inject
    private MinioClient minioClient;
    @Inject
    private MinioConfig minioConfig;

    @Inject
    ImageMilvusMapper imageMilvusMapper;
    @Inject
    private EmbeddingService embeddingService;
    public MilvusResp add(Long imageId,String imageName,UploadedFile file) throws MinioException, IOException, NoSuchAlgorithmException, InvalidKeyException, NoApiKeyException, UploadFileException {
        String url = uploadFile(file);
        MultiModalEmbeddingResult multiModalEmbeddingResult = embeddingService.embedding(1, Collections.singletonList(url));
        List<Float> collect = multiModalEmbeddingResult.getOutput().getEmbedding().stream()
                .map(d -> d.floatValue())
                .collect(Collectors.toList());
        ImageModel model=new ImageModel();
        model.setImageName(imageName);
        model.setId(imageId);
        model.setImageVector(normalizeVector(collect));
        imageMilvusMapper.insert(model);
        MilvusResp milvusResp = new MilvusResp();
        milvusResp.setSuccess(true);
        return milvusResp;
    }
    public MilvusResp<List<MilvusResult<ImageModel>>> search(UploadedFile file) throws MinioException, IOException, NoSuchAlgorithmException, InvalidKeyException, NoApiKeyException, UploadFileException {
        String url = uploadFile(file);
        MultiModalEmbeddingResult multiModalEmbeddingResult = embeddingService.embedding(1, Collections.singletonList(url));
        List<Float> v = multiModalEmbeddingResult.getOutput().getEmbedding().stream()
                .map(d -> d.floatValue())
                .collect(Collectors.toList());
        MilvusResp<List<MilvusResult<ImageModel>>> query = imageMilvusMapper.
                queryWrapper().vector(normalizeVector(v))
                .topK(1).query(ImageModel::getId,ImageModel::getImageName);
        return query;
    }
 
    private String uploadFile(UploadedFile file) throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {
        String bucketName = minioConfig.getBucketName();
        String  objectName= UUID.randomUUID().toString()+".jpg";
        InputStream inputStream = file.getContent();
        minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(inputStream, file.getContentSize(), -1)
                        .contentType(file.getContentType())
                        .build()
        );
        return minioConfig.getEndpoint()+"/"+bucketName+"/"+objectName;
    }
    public static List<Float> normalizeVector(List<Float> vector) {
        double sumOfSquares = 0.0;
        for (float value : vector) {
            sumOfSquares += value * value;
        }
        double magnitude = Math.sqrt(sumOfSquares);

        List<Float> normalizedVector = new ArrayList<>();
        for (float value : vector) {
            normalizedVector.add((float) (value / magnitude));
        }
        return normalizedVector;
    }
}